/*
 * pricer_test.cpp
 *
 *  Created on: Mar 14, 2009
 *      Author: genady
 */
#include <iostream>
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>
#include <utility>
#include <vector>
#include <cmath>


#include "pricer_test.hpp"
#include "../statistics/inverse_normal_distribution.hpp"
#include "../pricer/pricer.hpp"
#include "../utils/math_utils.hpp"
#include "../simulation/price_model.hpp"
#include "../simulation/price_simulator.hpp"

using namespace std;

// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( PricerTest );


void
PricerTest::setUp()
{
}


void
PricerTest::tearDown()
{
}


void
PricerTest::testPriceEvaluation()
{
	    cout<<"testPriceEvaluation"<<endl;
		pricer pr;
		pair<double,double> eval = pr.evaluate(40.0, 0.5, 0.16, 0.2, 0.95);
		cout << "PriceEvaluation(40.0, 0.5, 0.16, 0.2, 0.95): " << eval.first << " < price < " << eval.second << endl;

	//CPPUNIT_FAIL( "not implemented" );
		CPPUNIT_ASSERT_EQUAL( 0, 0 );
}

void
PricerTest::testInverseNormalCDF()
{
	cout<<"testInverseNormalCDF"<<endl;
	double mean = 0;
	double rms = 1;
	InverseNormalCDF invNormCDF( mean, rms );
//	while( true ) {
//		string input;
//		cout << "Enter confidence level (0 < confidence < 1): ";
//		getline( cin, input );
//		if( input.size() <= 1 )
//			break; // exit
//		istringstream is( input );
//		double confidence;
//		is >> confidence;
//		double approximation = 0;
//		try {
//			approximation = invNormCDF.approximation( 0.5*(1.0 - confidence) );
//			double lMargin = mean + approximation*rms;
//			double rMargin = 2.0*mean - lMargin;
//			cout << "Confidence interval: (" << lMargin << ", " << rMargin << ")" << endl;
//		} catch( invalid_argument &err ) {
//			cout << "Error: " << err.what() << endl;
//		}
	for (int i = 1; i<10;i++)
	{
		double confidence = 1.0-pow(2.0, -i);
		double approximation = invNormCDF.approximation( 0.5*(1.0 - confidence) );
		double lMargin = mean + approximation*rms;
		double rMargin = 2.0*mean - lMargin;
		cout << "Confidence interval: (" << lMargin << ", " << rMargin << ")" << endl;

	}

	CPPUNIT_ASSERT_EQUAL( 0, 0 );
}

void PricerTest::testExpPair()
{
    cout<<"testExpPair"<<endl;
    std::pair<double,double> pair_(1.0, 2.0);
	std::pair<double,double> exp_pair = exp(pair_);
	cout<<"pair ("<<exp_pair.first<<", "<<exp_pair.second<<")"<<endl;
	CPPUNIT_ASSERT_EQUAL( 0, 0 );

}

void PricerTest::testStockPriceModel()
{
	// taking data from example 13.1 in [J.Hull]
	cout << "testStockPriceModel(s0=40, mu=0.16, sigma=0.2, dt=0.01)" << endl;
	SPModelProps spModelProps;
	StockPriceModel spModel( spModelProps.setInitialPrice( 40.0 ).setExpectedReturn( 0.16 ).setVolatility( 0.2 ) );
	double dt = 0.01;
	vector<double> prices;
	double sT;
	for( int n = 0; n < 100; n++ ) {
		for( int i = 0; i < 50; i++ ) // half year period
			sT = spModel.getNextPrice( dt );
		prices.push_back( sT );
		spModel.resetProps( spModelProps );
	}
	SampleEstimations estimations ( prices );
	double meanPrice = estimations.getMean();
	double priceVariance = estimations.getVariance();
	double stdDeviation = sqrt( priceVariance );
	double left95Margin = meanPrice - 1.96*stdDeviation;
	double right95Margin = meanPrice + 1.96*stdDeviation;
	cout << "mean end price=" << meanPrice << "; std deviation=" << stdDeviation;
	cout << "; 95% interval=" << left95Margin << ", " << right95Margin << endl;
	// compare to example 13.1 in [J.Hull]
	int test = meanPrice > 32.55 && meanPrice < 56.56 ? 0 : 1;

	CPPUNIT_ASSERT_EQUAL( 0, test );
}

void PricerTest::testStockPriceSimulator()
{
	SPModelProps spModelProps;
	// taking data from example 13.1 in [J.Hull]
	spModelProps.setInitialPrice( 40.0 ).setExpectedReturn( 0.16 ).setVolatility( 0.2 );
	SPExperiment spExperiment;
	// run experiment with ORDERED_ENDPOINTS results - half year period
	spExperiment.setSPModelProps( spModelProps )
		.setNumberOfRuns( 100 ).setNumberOfPoints( 500 ).setTimeInterval( 0.001 )
		.setResultType( ORDERED_ENDPOINTS );
	cout << "testStockPriceSimulator([s0=40, mu=0.16, sigma=0.2], [nRuns=100, nPoints=500, dt=0.001, rType=ORDERED_ENDPOINTS])" << endl;
	StockPriceSimulator spSimulator;
	spSimulator.runExperiment( spExperiment );
	vector<double> results = spSimulator.getResults();
	SampleEstimations estimations ( results );
	double meanPrice = estimations.getMean();
	double priceVariance = estimations.getVariance();
	double stdDeviation = sqrt( priceVariance );
	double left95Margin = meanPrice - 1.96*stdDeviation;
	double right95Margin = meanPrice + 1.96*stdDeviation;
	cout << "mean end price=" << meanPrice << "; std deviation=" << stdDeviation;
	cout << "; 95% interval=" << left95Margin << ", " << right95Margin << endl;
	// compare to example 13.1 in [J.Hull]
	int test = meanPrice > 32.55 && meanPrice < 56.56 ? 0 : 1;

	CPPUNIT_ASSERT_EQUAL( 0, test );
}
